home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / serial.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  9KB  |  415 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   *  Serial Line Emulation
  5.   *
  6.   * (c) 1996, 1997 Stefan Reinauer <stepan@linux.de>
  7.   * (c) 1997 Christian Schmitt <schmitt@freiburg.linux.de>
  8.   *
  9.   */
  10.  
  11. #include "sysconfig.h"
  12. #include "sysdeps.h"
  13.  
  14. #include "config.h"
  15. #include "options.h"
  16. #include "uae.h"
  17. #include "memory.h"
  18. #include "custom.h"
  19. #include "readcpu.h"
  20. #include "newcpu.h"
  21. #include "cia.h"
  22.  
  23. #undef POSIX_SERIAL
  24. /* Some more or less good way to determine whether we can safely compile in
  25.  * the serial stuff. I'm certain it breaks compilation on some systems. */
  26. #if defined HAVE_SYS_TERMIOS_H && defined HAVE_POSIX_OPT_H && defined HAVE_SYS_IOCTL_H && defined HAVE_TCGETATTR
  27. #define POSIX_SERIAL
  28. #endif
  29.  
  30. #ifdef POSIX_SERIAL
  31. #include <termios.h>
  32. #include <unistd.h>
  33. #include <sys/ioctl.h>
  34. #endif
  35.  
  36. #if !defined B300 || !defined B1200 || !defined B2400 || !defined B4800 || !defined B9600
  37. #undef POSIX_SERIAL
  38. #endif
  39. #if !defined B19200 || !defined B57600 || !defined B115200 || !defined B230400
  40. #undef POSIX_SERIAL
  41. #endif
  42.  
  43. #ifndef O_NONBLOCK
  44. #define O_NONBLOCK O_NDELAY
  45. #endif
  46.  
  47. #define SERIALDEBUG 1 /* 0, 1, 2 3 */
  48. #define MODEMTEST   0 /* 0 or 1 */
  49.  
  50. void serial_open (void);
  51. void serial_close (void);
  52. void serial_init (void);
  53. void serial_exit (void);
  54.  
  55. void serial_dtr_on (void);
  56. void serial_dtr_off (void);
  57.  
  58. void serial_flush_buffer (void);
  59. static int serial_read (char *buffer);
  60.  
  61. int serial_readstatus (void);
  62. uae_u16 serial_writestatus (int, int);
  63.  
  64. uae_u16 SERDATR (void);
  65.  
  66. int  SERDATS (void);
  67. void  SERPER (uae_u16 w);
  68. void  SERDAT (uae_u16 w);
  69.  
  70. static char inbuf[1024], outbuf[1024];
  71. static int inptr, inlast, outlast;
  72.  
  73. int waitqueue=0,
  74.     carrier=0,
  75.     serdev=0,
  76.     dsr=0,
  77.     dtr=0,
  78.     isbaeh=0,
  79.     doreadser=0,
  80.     serstat=-1;
  81.  
  82. int sd = -1;
  83.  
  84. #ifdef POSIX_SERIAL
  85.     struct termios tios;
  86. #endif
  87.  
  88. uae_u16 serper=0,serdat;
  89.  
  90. void SERPER (uae_u16 w)
  91. {
  92.     int baud=0, pspeed;
  93.  
  94.     if (!currprefs.use_serial)
  95.     return;
  96.  
  97. #if defined POSIX_SERIAL
  98.     if (serper == w)  /* don't set baudrate if it's already ok */
  99.     return;
  100.     serper=w;
  101.  
  102.     if (w&0x8000)
  103.     fprintf (stdout, "SERPER: 9bit transmission not implemented.\n");
  104.  
  105.     switch (w & 0x7fff) {
  106.      /* These values should be calculated by the current
  107.       * color clock value (NTSC/PAL). But this solution is
  108.       * easy and it works.
  109.       */
  110.  
  111.      case 0x2e9b:
  112.      case 0x2e14: baud=300; pspeed=B300; break;
  113.      case 0x170a:
  114.      case 0x0b85: baud=1200; pspeed=B1200; break;
  115.      case 0x05c2:
  116.      case 0x05b9: baud=2400; pspeed=B2400; break;
  117.      case 0x02e9:
  118.      case 0x02e1: baud=4800; pspeed=B4800; break;
  119.      case 0x0174:
  120.      case 0x0170: baud=9600; pspeed=B9600; break;
  121.      case 0x00b9:
  122.      case 0x00b8: baud=19200; pspeed=B19200; break;
  123.      case 0x005c:
  124.      case 0x005d: baud=38400; pspeed=B38400; break;
  125.      case 0x003d: baud=57600; pspeed=B57600; break;
  126.      case 0x001e: baud=115200; pspeed=B115200; break;
  127.      case 0x000f: baud=230400; pspeed=B230400; break;
  128.      default:
  129.     fprintf (stdout,"SERPER: unsupported baudrate (0x%04x) %d\n",w&0x7fff,
  130.          (unsigned int)(3579546.471/(double)((w&0x7fff)+1)));  return;
  131.     }
  132.  
  133.     /* Only access hardware when we own it */
  134.     if (serdev == 1) {
  135.     if (tcgetattr (sd, &tios) < 0) {
  136.         fprintf (stderr, "SERPER: TCGETATTR failed\n");
  137.         return;
  138.     }
  139.  
  140.     if (cfsetispeed (&tios, pspeed) < 0) {    /* set serial input speed */
  141.         fprintf (stderr, "SERPER: CFSETISPEED (%d bps) failed\n", baud);
  142.         return;
  143.     }
  144.     if (cfsetospeed (&tios, pspeed) < 0) {    /* set serial output speed */
  145.         fprintf (stderr, "SERPER: CFSETOSPEED (%d bps) failed\n", baud);
  146.         return;
  147.     }
  148.  
  149.     if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
  150.         fprintf (stderr, "SERPER: TCSETATTR failed\n");
  151.         return;
  152.     }
  153.     }
  154. #endif
  155.  
  156. #if SERIALDEBUG > 0
  157.     if (serdev == 1)
  158.     fprintf (stdout, "SERPER: baudrate set to %d bit/sec\n", baud);
  159. #endif
  160. }
  161.  
  162. /* Not (fully) implemented yet:
  163.  *
  164.  *  -  Something's wrong with the Interrupts.
  165.  *     (NComm works, TERM does not. TERM switches to a
  166.  *     blind mode after a connect and wait's for the end
  167.  *     of an asynchronous read before switching blind
  168.  *     mode off again. It never gets there on UAE :-< )
  169.  *
  170.  *  -  RTS/CTS handshake, this is not really neccessary,
  171.  *     because you can use RTS/CTS "outside" without
  172.  *     passing it through to the emulated Amiga
  173.  *
  174.  *  -  ADCON-Register ($9e write, $10 read) Bit 11 (UARTBRK)
  175.  *     (see "Amiga Intern", pg 246)
  176.  */
  177.  
  178. void SERDAT (uae_u16 w)
  179. {
  180.     unsigned char z;
  181.  
  182.     if (!currprefs.use_serial)
  183.     return;
  184.  
  185.     z = (unsigned char)(w&0xff);
  186.  
  187.     if (currprefs.serial_demand && !dtr) {
  188.     if (!isbaeh) {
  189.         fprintf(stdout,"SERDAT: Baeh.. Your software needs SERIAL_ALWAYS to work properly.\n");
  190.         isbaeh=1;
  191.     }
  192.     return;
  193.     } else {
  194.     outbuf[outlast++] = z;
  195.     if (outlast == sizeof outbuf)
  196.         serial_flush_buffer();
  197.     }
  198.  
  199. #if SERIALDEBUG > 2
  200.     fprintf (stderr, "SERDAT: wrote 0x%04x\n", w);
  201. #endif
  202.  
  203.     serdat|=0x2000; /* Set TBE in the SERDATR ... */
  204.     intreq|=1;      /* ... and in INTREQ register */
  205.     return;
  206. }
  207.  
  208. uae_u16 SERDATR (void)
  209. {
  210.     if (!currprefs.use_serial)
  211.     return 0;
  212. #if SERIALDEBUG > 2
  213.     fprintf (stdout, "SERDATR: read 0x%04x\n", serdat);
  214. #endif
  215.     waitqueue = 0;
  216.     return serdat;
  217. }
  218.  
  219. int SERDATS (void)
  220. {
  221.     unsigned char z;
  222.  
  223.     if (!serdev)           /* || (serdat&0x4000)) */
  224.     return 0;
  225.  
  226.     if (waitqueue == 1) {
  227.     intreq |= 0x0800;
  228.     return 1;
  229.     }
  230.  
  231.     if ((serial_read ((char *)&z)) == 1) {
  232.     waitqueue = 1;
  233.     serdat = 0x4100; /* RBF and STP set! */
  234.     serdat |= ((unsigned int)z) & 0xff;
  235.     intreq |= 0x0800; /* Set RBF flag (Receive Buffer full) */
  236.  
  237. #if SERIALDEBUG > 1
  238.     fprintf (stdout, "SERDATS: received 0x%02x --> serdat==0x%04x\n",
  239.          (unsigned int)z, (unsigned int)serdat);
  240. #endif
  241.     return 1;
  242.     }
  243.     return 0;
  244. }
  245.  
  246. void serial_dtr_on(void)
  247. {
  248. #if SERIALDEBUG > 0
  249.     fprintf (stdout, "DTR on.\n");
  250. #endif
  251.     dtr=1;
  252.  
  253.     if (currprefs.serial_demand)
  254.     serial_open ();
  255. }
  256.  
  257. void serial_dtr_off(void)
  258. {
  259. #if SERIALDEBUG > 0
  260.     fprintf (stdout, "DTR off.\n");
  261. #endif
  262.     dtr=0;
  263.     if (currprefs.serial_demand)
  264.     serial_close ();
  265. }
  266.  
  267. static int serial_read (char *buffer)
  268. {
  269.     if (inptr < inlast) {
  270.     *buffer = inbuf[inptr++];
  271.     return 1;
  272.     }
  273.  
  274.     if (serdev == 1) {
  275.     inlast = read (sd, inbuf, sizeof inbuf);
  276.     inptr = 0;
  277.     if (inptr < inlast) {
  278.         *buffer = inbuf[inptr++];
  279.         return 1;
  280.     }
  281.     }
  282.  
  283.     return 0;
  284. }
  285.  
  286. void serial_flush_buffer(void)
  287. {
  288.     if (serdev == 1) {
  289.     if (outlast) {
  290.         if (sd != 0) {
  291.         write (sd, outbuf, outlast);
  292.         }
  293.     }
  294.     outlast = 0;
  295.     } else {
  296.       outlast = 0;
  297.       inptr = 0;
  298.       inlast = 0;
  299.     }
  300. }
  301.  
  302. int serial_readstatus(void)
  303. {
  304.     int status = 0;
  305.  
  306. #ifdef POSIX_SERIAL
  307.     ioctl (sd, TIOCMGET, &status);
  308.  
  309.     if (status & TIOCM_CAR) {
  310.     if (!carrier) {
  311.         ciabpra |= 0x20; /* Push up Carrier Detect line */
  312.         carrier = 1;
  313. #if SERIALDEBUG > 0
  314.         fprintf (stdout, "Carrier detect.\n");
  315. #endif
  316.     }
  317.     } else {
  318.     if (carrier) {
  319.         ciabpra &= ~0x20;
  320.         carrier = 0;
  321. #if SERIALDEBUG > 0
  322.         fprintf (stdout, "Carrier lost.\n");
  323. #endif
  324.     }
  325.     }
  326.  
  327.     if (status & TIOCM_DSR) {
  328.     if (!dsr) {
  329.         ciabpra |= 0x08; /* DSR ON */
  330.         dsr = 1;
  331.     }
  332.     } else {
  333.     if (dsr) {
  334.         ciabpra &= ~0x08;
  335.         dsr = 0;
  336.     }
  337.     }
  338. #endif
  339.     return status;
  340. }
  341.  
  342. uae_u16 serial_writestatus (int old, int nw)
  343. {
  344.     if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00)
  345.     serial_dtr_on();
  346.     if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80)
  347.     serial_dtr_off();
  348.  
  349.     if ((old & 0x40) != (nw & 0x40))
  350.     fprintf (stdout, "RTS %s.\n", ((nw & 0x40) == 0x40) ? "set" : "cleared");
  351.  
  352.     if ((old & 0x10) != (nw & 0x10))
  353.     fprintf (stdout, "CTS %s.\n", ((nw & 0x10) == 0x10) ? "set" : "cleared");
  354.  
  355.     return nw; /* This value could also be changed here */
  356. }
  357.  
  358. void serial_open(void)
  359. {
  360.     if (serdev == 1)
  361.     return;
  362.  
  363.     if ((sd = open (sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) {
  364.     fprintf (stdout, "Error: Could not open Device %s\n", sername);
  365.     return;
  366.     }
  367.  
  368.     serdev = 1;
  369.  
  370. #ifdef POSIX_SERIAL
  371.     if (tcgetattr (sd, &tios) < 0) {        /* Initialize Serial tty */
  372.     fprintf (stderr, "Serial: TCGETATTR failed\n");
  373.     return;
  374.     }
  375.     cfmakeraw (&tios);
  376.  
  377. #ifndef MODEMTEST
  378.     tios.c_cflag &= ~CRTSCTS; /* Disable RTS/CTS */
  379. #else
  380.     tios.c_cflag |= CRTSCTS; /* Enabled for testing modems */
  381. #endif
  382.  
  383.     if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
  384.     fprintf (stderr,"Serial: TCSETATTR failed\n");
  385.     return;
  386.     }
  387. #endif
  388. }
  389.  
  390. void serial_close (void)
  391. {
  392.     if (sd != 0)
  393.     close(sd);
  394.     serdev = 0;
  395. }
  396.  
  397. void serial_init (void)
  398. {
  399.     if (!currprefs.use_serial)
  400.     return;
  401.  
  402.     if (!currprefs.serial_demand)
  403.     serial_open ();
  404.  
  405.     serdat = 0x2000;
  406.     return;
  407. }
  408.  
  409. void serial_exit (void)
  410. {
  411.     serial_close ();    /* serial_close can always be called because it    */
  412.     dtr = 0;        /* just closes *opened* filehandles which is ok    */
  413.     return;        /* when exiting.                */
  414. }
  415.